﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.IO;
using System.Text;
using System.Windows.Forms;
using CodeTalk.CTSpeechCommands;

namespace CodeTalk
{
    public partial class Form1 : Form
    {
        OutputHandler currentOutputHandler;
        InputHandler currentInputHandler;
        GUIHandler currentGUIHandler;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            DataGridViewComboBoxColumn lst = (DataGridViewComboBoxColumn)SymbolView.Columns[0];
            for (int i = 0; i < (int)CodeTalk.SymbolCategory.nSymbolCategories; i++)
            {
                lst.Items.Add(((SymbolCategory)i).ToString());
                symbolCategoryComboBox.Items.Add(((SymbolCategory)i).ToString());
            }

            lst = (DataGridViewComboBoxColumn)SymbolView.Columns[4];
            lst.Items.AddRange("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");

            string libPath = Application.StartupPath + "\\libraries\\";
            if (Directory.Exists(libPath))
            {
                libraryPathTextBox.Text = libPath;
            }
            
            currentOutputHandler = new OutputHandler();
            currentGUIHandler = new GUIHandler(feedbackTextBox, AlternativesListBox, audioProgressBar, RefreshSymbolView);

            currentInputHandler = new InputHandler();

            FillSymbolView(new CodeSymbol[] { });

            FillTextCommandsView(new TextCommand[] { });
            FillCommandsView(new SpeechCommand[] { });

            expandButton.Text = "Expand >>";
            this.Size = new Size(collapsedSizeWidth, collapsedSizeHeight);
            isExpanded = false;

            SetWindowTitle();
        }

        public void RefreshSymbolView()
        {
            if (currentMode != null && currentMode.CurrentContext != null)
            {
                FillSymbolView(currentMode.CurrentContext.Symbols);
            }
        }

        private void SetWindowTitle()
        {
            if (currentMode != null)
            {
                string contextName = "";
                if (currentMode.CurrentContext != null)
                {
                    contextName = currentMode.CurrentContext.Name;
                    if (currentMode.CurrentContext.IsLibrary)
                        contextName += " (library)";
                }

                if (contextName.Length > 0)
                    this.Text = currentMode.Name + ", " + contextName + " - CodeTalk";
                else
                    this.Text = currentMode.Name + ", (no context) - CodeTalk";
            }
            else
            {
                this.Text = "CodeTalk";
            }
        }

        private bool ValidateSpechModeAndContext()
        {
            if (currentMode == null)
            {
                MessageBox.Show("No Speech mode loaded.", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return false;
            }
            if (currentMode.CurrentContext == null)
            {
                MessageBox.Show("No Context loaded.", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return false;
            }
            return true;
        }

        #region Symbol stuff
        string OriginalSymbolSpokenForm = "";
        void FillSymbolView(IEnumerable<CodeSymbol> symbols)
        {
            SymbolView.Rows.Clear();

            foreach (var s in symbols)
            {
                SymbolView.Rows.Add(s.CategoryString, s.WrittenForm, s.SpokenForm, s.Permanent, s.Parameters.ToString(), s.ParentType, s.File, s.Solution, s.SymbolID.ToString());
            }
        }

        private void newSymbolButton_Click(object sender, EventArgs e)
        {
            if (!ValidateSpechModeAndContext()) return;

            if (symbolCategoryComboBox.Text == null || symbolCategoryComboBox.Text.Trim().Length == 0)
            {
                MessageBox.Show("Choose a symbol category. ");
                return;
            }

            if (newSpokenFormTextBox.Text == null || newSpokenFormTextBox.Text.Trim().Length == 0)
            {
                MessageBox.Show("Specify a symbol name. ");
                return;
            }

            SymbolCategory newCategory = (SymbolCategory)Enum.Parse(typeof(SymbolCategory), symbolCategoryComboBox.Text);

            string errorMessage = "";

            uint id = currentMode.CurrentContext.CreateNewSymbol(newSpokenFormTextBox.Text, newCategory, currentMode, ref errorMessage);

            if (id == 0)
            {
                MessageBox.Show(errorMessage, "Error creating symbol!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            RefreshSymbolView();
            currentMode.RecompileGrammar();
        }

        private void deleteSymbolButton_Click(object sender, EventArgs e)
        {
            if (!ValidateSpechModeAndContext()) return;

            if (SymbolView.SelectedRows.Count == 1)
            {
                uint symbolID = Convert.ToUInt32(SymbolView["SymbolID", SymbolView.SelectedRows[0].Index].Value);
                currentMode.CurrentContext.DeleteSymbolWithID(symbolID);
                RefreshSymbolView();
                currentMode.RecompileGrammar();
            }
            else if (SymbolView.SelectedRows.Count == 0)
            {
                MessageBox.Show("Select a row to delete.", "CodeTalk");
            }
            else
            {
                MessageBox.Show("Select only one row to delete.", "CodeTalk");
            }
        }

        private void SymbolView_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
        }

        private void SymbolView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {
            OriginalSymbolSpokenForm = (string)SymbolView["SymbolSpokenForm", e.RowIndex].Value;
        }

        private void SymbolView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            if (!ValidateSpechModeAndContext()) return;

            string newSymbolSpokenForm = (string)SymbolView["SymbolSpokenForm", e.RowIndex].Value;
            if (newSymbolSpokenForm != OriginalSymbolSpokenForm)
            {
                SymbolCategory category = CodeTalk.SymbolCategory.Open;
                string categoryString = (string)SymbolView["SymbolCategory", e.RowIndex].Value;
                for (int i = 0; i < (int)CodeTalk.SymbolCategory.nSymbolCategories; i++)
                {
                    if (categoryString == ((SymbolCategory)i).ToString())
                    {
                        category = (SymbolCategory)i;
                        break;
                    }
                }

                string errorMessage = "";
                if (!currentMode.CurrentContext.ValidateNewSymbol(newSymbolSpokenForm, category, currentMode, ref errorMessage))
                {
                    MessageBox.Show("Could not change symbol's spoken form. Reason: " + errorMessage, "Error editing symbol", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    SymbolView["SymbolSpokenForm", e.RowIndex].Value = OriginalSymbolSpokenForm;
                    return;
                }
            }

            CommitSymbolViewRow(currentMode.CurrentContext.Symbols, e.RowIndex);
            currentMode.RecompileGrammar();
        }

        void CommitSymbolViewRow(IEnumerable<CodeSymbol> symbols, int rowIndex)
        {
            int symbolID = Convert.ToInt32(SymbolView["SymbolID", rowIndex].Value);

            foreach (var s in symbols)
            {
                if (s.SymbolID == symbolID)
                {
                    s.WrittenForm = (string)SymbolView["SymbolWrittenForm", rowIndex].Value;
                    s.SpokenForm = ((string)SymbolView["SymbolSpokenForm", rowIndex].Value).ToLowerInvariant();
                    s.CategoryString = (string)SymbolView["SymbolCategory", rowIndex].Value;
                    s.Permanent = Convert.ToBoolean(SymbolView["SymbolPermanent", rowIndex].Value);
                    s.Parameters = Convert.ToInt32(SymbolView["SymbolParameters", rowIndex].Value);
                    s.ParentType = (string)SymbolView["SymbolParentType", rowIndex].Value;
                    s.File = (string)SymbolView["SymbolFile", rowIndex].Value;
                    s.Solution = (string)SymbolView["SymbolSolution", rowIndex].Value;

                    break;
                }
            }
        }
        #endregion

        #region Text Command stuff
        void FillTextCommandsView(IEnumerable<TextCommand> textCommands)
        {
            TextCommandsView.Rows.Clear();

            foreach (var tc in textCommands)
                TextCommandsView.Rows.Add(tc.WrittenForm, tc.SpokenForm, tc.UndoText, tc.AddPreSpace, tc.RemPreSpace, tc.Active);
        }

        private void createTCButton_Click(object sender, EventArgs e)
        {
            if (currentMode == null)
            {
                MessageBox.Show("No Speech mode loaded.", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            if (writtenTCTextBox.Text.Length == 0)
            {
                MessageBox.Show("Text command must have a written form. ", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            if (spokenTCTextBox.Text.Trim().Length == 0)
            {
                MessageBox.Show("Text command must have a spoken form. ", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            string errorMessage = "";
            if (currentMode.CreateNewTextCommand(writtenTCTextBox.Text, spokenTCTextBox.Text, ref errorMessage))
                FillTextCommandsView(currentMode.TextCommands);
            else
                MessageBox.Show(errorMessage, "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

        private void deleteTCButton_Click(object sender, EventArgs e)
        {
            if (currentMode == null)
            {
                MessageBox.Show("No Speech mode loaded.", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            if (TextCommandsView.SelectedRows.Count == 1)
            {
                string spokenForm = (string)TextCommandsView["TCSpokenForm", TextCommandsView.SelectedRows[0].Index].Value;
                currentMode.DeleteTextCommandWithSpokenForm(spokenForm);
                FillTextCommandsView(currentMode.TextCommands);
                currentMode.RecompileGrammar();
            }
            else if (TextCommandsView.SelectedRows.Count == 0)
            {
                MessageBox.Show("Select a row to delete.");
            }
            else
            {
                MessageBox.Show("Select only one row to delete.");
            }
        }

        private void TextCommandsView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {
        }

        private void TextCommandsView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            CommitTextCommandsViewRow(currentMode.TextCommands, e.RowIndex);
            currentMode.RecompileGrammar();
        }

        void CommitTextCommandsViewRow(IEnumerable<TextCommand> textCommands, int rowIndex)
        {
            string spokenForm = (string)TextCommandsView["TCSpokenForm", rowIndex].Value;

            foreach (var tc in textCommands)
            {
                if (tc.SpokenForm == spokenForm)
                {
                    tc.WrittenForm = (string)TextCommandsView["TCWrittenForm", rowIndex].Value;
                    tc.UndoText = (string)TextCommandsView["UndoText", rowIndex].Value;
                    tc.AddPreSpace = Convert.ToBoolean(TextCommandsView["AddPreSpace", rowIndex].Value);
                    tc.RemPreSpace = Convert.ToBoolean(TextCommandsView["RemPreSpace", rowIndex].Value);
                    tc.Active = Convert.ToBoolean(TextCommandsView["TCActive", rowIndex].Value);

                    break;
                }
            }
        }
        #endregion

        #region Speech Command stuff
        void FillCommandsView(IEnumerable<SpeechCommand> commands)
        {
            CommandsView.Rows.Clear();

            foreach (var c in commands)
                CommandsView.Rows.Add(c.Active, c.Name, c.Description);
        }

        private void CommandsView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {

        }

        private void CommandsView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            CommitCommandsViewRow(currentMode.SpeechCommands, e.RowIndex);
            currentMode.RecompileGrammar();
        }

        void CommitCommandsViewRow(IEnumerable<SpeechCommand> speechCommands, int rowIndex)
        {
            string name = (string)CommandsView["SCName", rowIndex].Value;

            foreach (var sc in speechCommands)
            {
                if (sc.Name == name)
                {
                    sc.Active = Convert.ToBoolean(CommandsView["SCActive", rowIndex].Value);
                    break;
                }
            }
        }
        #endregion

        #region Speech mode stuff
        SpeechMode currentMode;

        #endregion

        #region Library stuff

        List<Context> loadedLibraries;
        
        private void LoadAvailableLibraries()
        {
            if (libraryPathTextBox.Text == "")
                return;

            if (currentMode == null)
            {
                MessageBox.Show("No Speech mode loaded.", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            if (loadedLibraries == null) loadedLibraries = new List<Context>();

            loadedLibraries.Clear();
            currentMode.ClearLibrariesUsed();
            if (libraryPathTextBox.Text.Trim().Length > 0 && Directory.Exists(libraryPathTextBox.Text))
            {
                foreach (var fileName in Directory.GetFiles(libraryPathTextBox.Text, "*.ctlib"))
                {
                    Context newLib = Context.LoadFromFile(fileName);
                    if (newLib != null) loadedLibraries.Add(newLib);
                }
            }

            FillLibrariesListBox(loadedLibraries);
        }

        private void FillLibrariesListBox(IEnumerable<Context> libraries)
        {
            librariesCheckedListBox.Items.Clear();
            foreach (var lib in loadedLibraries)
                librariesCheckedListBox.Items.Add(lib.Name, currentMode.IsLibraryUsed(lib.Name));
        }

        private void librariesCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (!ValidateSpechModeAndContext())
            {
                e.NewValue = CheckState.Unchecked;
                return;
            }

            string name = (string)librariesCheckedListBox.Items[e.Index];
            if (e.NewValue == CheckState.Checked)
            {
                Context checkedLib = null;
                foreach (var lib in loadedLibraries)
                {
                    if (lib.Name == name) checkedLib = lib;
                }
                currentMode.AddLibraryUsed(checkedLib);
            }
            else
            {
                currentMode.RemoveLibraryUsed(name);
            }
        }

        private void changeLibraryPathButton_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbd = new FolderBrowserDialog();

            fbd.Description = "Select the folder to search for libraries...";
            //fbd.RootFolder = Environment.SpecialFolder.MyDocuments;
            fbd.SelectedPath = Application.StartupPath;

            if (fbd.ShowDialog() == DialogResult.OK)
            {
                libraryPathTextBox.Text = fbd.SelectedPath;
                LoadAvailableLibraries();
            }
        }

        #endregion

        #region Tool strip stuff
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void newSpeechModeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (currentMode != null &&
                MessageBox.Show("Do you want to save the current speech mode before creating a new one?",
                "Save current speech mode?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                if (!currentMode.Save())
                    MessageBox.Show("Error saving speech mode!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            SaveFileDialog saveFileDialog1 = new SaveFileDialog();

            saveFileDialog1.Filter = "Speech mode file (*.csm)|*.csm";
            saveFileDialog1.FilterIndex = 1;
            saveFileDialog1.RestoreDirectory = true;

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    Context lastContext = null;
                    if (currentMode != null)
                    {
                        lastContext = currentMode.CurrentContext;
                        currentMode.Deactivate();
                    }
                    string path = saveFileDialog1.FileName;
                    currentMode = new SpeechMode(path, currentOutputHandler, currentGUIHandler, lastContext);

                    FillTextCommandsView(currentMode.TextCommands);
                    FillCommandsView(currentMode.SpeechCommands);
                    ActionManager.ClearHistory();
                    LoadAvailableLibraries();
                    SetWindowTitle();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error creating new Speech mode: " + ex, "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void newContextToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (currentMode == null)
            {
                MessageBox.Show("No Speech mode loaded.", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            if (currentMode.CurrentContext != null &&
                MessageBox.Show("Do you want to save the current Context before creating a new one?",
                "Save current Context?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                if (!currentMode.CurrentContext.Save())
                    MessageBox.Show("Error saving Context!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            SaveFileDialog saveFileDialog1 = new SaveFileDialog();

            saveFileDialog1.Filter = "Context file (*.ctc)|*.ctc";
            saveFileDialog1.FilterIndex = 1;
            saveFileDialog1.RestoreDirectory = true;

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    string path = saveFileDialog1.FileName;
                    currentMode.SetContext(new Context(path));

                    currentInputHandler.Init(currentMode);
                    ListeningRadioButton.Checked = true;
                    ActionManager.ClearHistory();

                    SetWindowTitle();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error creating new Context: " + ex, "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void openSpeechModeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (currentMode != null &&
                MessageBox.Show("Do you want to save the current speech mode before opening another?",
                "Save current speech mode?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                if (!currentMode.Save())
                    MessageBox.Show("Error saving speech mode!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.InitialDirectory = Application.StartupPath;
            openFileDialog1.Filter = "Speech mode file (*.csm)|*.csm";
            openFileDialog1.FilterIndex = 1;
            openFileDialog1.RestoreDirectory = true;
            openFileDialog1.CheckFileExists = true;
            openFileDialog1.Multiselect = false;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    Context lastContext = null;
                    if (currentMode != null)
                    {
                        lastContext = currentMode.CurrentContext;
                        currentMode.Deactivate();
                    }
                    string path = openFileDialog1.FileName;
                    currentMode = SpeechMode.LoadFromFile(path, currentOutputHandler, currentGUIHandler, lastContext);

                    //currentInputHandler.Listening = false;
                    //currentInputHandler.SetSpeechMode(currentMode);

                    FillTextCommandsView(currentMode.TextCommands);
                    FillCommandsView(currentMode.SpeechCommands);
                    ActionManager.ClearHistory();
                    LoadAvailableLibraries();
                    SetWindowTitle();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error loading Speech mode: " + ex, "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void openContextToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (currentMode == null)
            {
                MessageBox.Show("No Speech mode loaded.", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            if (currentMode.CurrentContext != null &&
                MessageBox.Show("Do you want to save the current Context before opening another?",
                "Save current Context?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                if (!currentMode.CurrentContext.Save())
                    MessageBox.Show("Error saving Context!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.InitialDirectory = Application.StartupPath;
            openFileDialog1.Filter = "Context file (*.ctc)|*.ctc|Library file (*.ctlib)|*.ctlib";
            openFileDialog1.FilterIndex = 1;
            openFileDialog1.RestoreDirectory = true;
            openFileDialog1.CheckFileExists = true;
            openFileDialog1.Multiselect = false;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    string path = openFileDialog1.FileName;
                    Context newContext = Context.LoadFromFile(path);

                    if (newContext != null)
                    {
                        currentMode.SetContext(newContext);
                        currentInputHandler.Init(currentMode);
                        ListeningRadioButton.Checked = true;
                        ActionManager.ClearHistory();
                    }
                    else
                        MessageBox.Show("Error loading Context!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);

                    RefreshSymbolView();
                    SetWindowTitle();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error loading Context: " + ex, "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void saveSpeechModeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (currentMode != null)
                    currentMode.Save();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error saving Speech mode: " + ex, "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void saveContextToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (currentMode != null && currentMode.CurrentContext != null)
                    currentMode.CurrentContext.Save();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error saving Context: " + ex, "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void saveAsSpeechModeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (currentMode == null)
            {
                MessageBox.Show("No Speech mode loaded.", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            SaveFileDialog saveFileDialog1 = new SaveFileDialog();

            saveFileDialog1.Filter = "Speech mode file (*.csm)|*.csm";
            saveFileDialog1.FilterIndex = 1;
            saveFileDialog1.RestoreDirectory = true;

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    string path = saveFileDialog1.FileName;
                    currentMode.SaveToFile(saveFileDialog1.FileName);

                    SetWindowTitle();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error saving Speech mode: " + ex, "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void saveAsContextToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!ValidateSpechModeAndContext()) return;

            SaveFileDialog saveFileDialog1 = new SaveFileDialog();

            saveFileDialog1.Filter = "Context file (*.ctc)|*.ctc";
            saveFileDialog1.FilterIndex = 1;
            saveFileDialog1.RestoreDirectory = true;

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    string path = saveFileDialog1.FileName;
                    currentMode.CurrentContext.SaveToFile(path);

                    SetWindowTitle();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error saving Context: " + ex, "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void convertContextToLibraryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!ValidateSpechModeAndContext()) return;

            SaveFileDialog saveFileDialog1 = new SaveFileDialog();

            saveFileDialog1.Filter = "CodeTalk Library file (*.ctlib)|*.ctlib";
            saveFileDialog1.FilterIndex = 1;
            saveFileDialog1.RestoreDirectory = true;

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    currentMode.CurrentContext.SaveAsLibrary(saveFileDialog1.FileName);
                    SetWindowTitle();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error saving Context as Library: " + ex, "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void transferSymbolToLibraryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!ValidateSpechModeAndContext())
                return;

            uint symbolID = 0;
            if (SymbolView.SelectedRows.Count == 1)
            {
                symbolID = Convert.ToUInt32(SymbolView["SymbolID", SymbolView.SelectedRows[0].Index].Value);
            }
            else if (SymbolView.SelectedRows.Count == 0)
            {
                MessageBox.Show("Select a row to transfer.", "CodeTalk");
                return;
            }
            else
            {
                MessageBox.Show("Select only one row to transfer.", "CodeTalk");
                return;
            }

            if (loadedLibraries.Count == 0)
            {
                MessageBox.Show("No libraries available to transfer to!", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            List<string> libraryNames = new List<string>();
            foreach (var lib in loadedLibraries)
                libraryNames.Add(lib.Name);

            LibrarySelector ls = new LibrarySelector();
            ls.SetItems(libraryNames.ToArray());
            if (ls.ShowDialog() == DialogResult.OK)
            {
                if (ls.SelectedItem == "")
                {
                    MessageBox.Show("No library selected!", "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                foreach (var lib in loadedLibraries)
                {
                    if (lib.Name == ls.SelectedItem)
                    {
                        CodeSymbol cs = currentMode.CurrentContext.GetSymbolWithID(symbolID);
                        string errMsg = "";
                        if (lib.CreateNewSymbol(cs.WrittenForm, cs.SpokenForm, cs.Category, currentMode, true, cs.ParentType, 
                            "", "", ref errMsg) == 0)
                        {
                            MessageBox.Show("Could not add symbol to library: " + errMsg, "CodeTalk", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            return;
                        }

                        lib.Save();
                        currentMode.CurrentContext.DeleteSymbolWithID(symbolID);
                        RefreshSymbolView();
                        currentMode.RecompileGrammar();
                    }
                }
            }
        }

        #endregion

        private void ListeningRadioButton_CheckedChanged(object sender, EventArgs e)
        {
            if (ListeningRadioButton.Checked)
            {
                if (!ValidateSpechModeAndContext())
                {
                    ListeningRadioButton.Checked = false;
                    OffRadioButton.Checked = true;
                    return;
                }
                currentInputHandler.Listening = true;
            }
            else
            {
                if (currentMode != null)
                    currentInputHandler.Listening = false;
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (currentMode != null)
            {
                DialogResult res;
                if (currentMode.CurrentContext != null)
                {
                    res = MessageBox.Show("Would you like to save changes to the Context '" + currentMode.CurrentContext.Name + "'?", 
                        "CodeTalk", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                    if (res == DialogResult.Yes)
                    {
                        currentMode.CurrentContext.Save();
                    }
                    else if (res == DialogResult.Cancel)
                    {
                        e.Cancel = true;
                        return;
                    }
                }
                res = MessageBox.Show("Would you like to save changes to the Speech mode '" + currentMode.Name + "'?", 
                    "CodeTalk", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (res == DialogResult.Yes)
                {
                    currentMode.Save();
                }
                else if (res == DialogResult.Cancel)
                {
                    e.Cancel = true;
                    return;
                }
            }
            currentInputHandler.Terminate();
        }

        private bool isExpanded = false;
        private int expandedSizeWidth = 636;
        private int expandedSizeHeight = 616;
        private int collapsedSizeWidth = 295;
        private int collapsedSizeHeight = 290;
        private void expandButton_Click(object sender, EventArgs e)
        {
            if (isExpanded)
            {
                expandButton.Text = "Expand >>";
                this.Size = new Size(collapsedSizeWidth, collapsedSizeHeight);
                isExpanded = false;
            }
            else
            {
                expandButton.Text = "Collaps <<";
                this.Size = new Size(expandedSizeWidth, expandedSizeHeight);
                isExpanded = true;
            }
        }

        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            //if (isExpanded)
            //{
            //    expandedSizeWidth = this.Size.Width;
            //    expandedSizeHeight = this.Size.Height;
            //}
        }
    }
}
